use std::mem;

use super::Chessboard;
use super::ChessPlayer;
use super::ChessResult;
use super::ChessAction;


#[derive(Eq, PartialEq, Debug)]
pub enum GameStage{
    Waiting, Put, Move, Over
}

///行动类型，落子，走子，吃子
enum Action{
    Put, Move, Eat
}

struct NextAction{
    pub player: u32,
    pub action: Action
}


/// 玩家轮换通过std::mem::swap(x, y)来实现
/// 这里面black和white不表示玩家棋子颜色，而表示先手后手
pub struct ChessRoom{
    ///kill count
    kill: u8,

    ///room id
    id: u32,

    ///room status
    stage: GameStage,

    ///next action
    next: NextAction,

    black: ChessPlayer,

    white: ChessPlayer,

    ///chessboard
    board: Chessboard,
}


impl ChessRoom{
    pub fn new(id: u32, black: ChessPlayer, white: ChessPlayer) -> ChessRoom{
        let next = NextAction{player: black.id(), action: Action::Put};
        let chessboard = Chessboard::new();
        ChessRoom{
            kill: 0u8,
            id,
            stage: GameStage::Put,
            next,
            black,
            white,
            board: chessboard,
        }
    }

    ///房间id
    pub fn id(&self) -> u32{
        self.id
    }

    pub fn game_stage(&self) -> &GameStage{
        &self.stage
    }

    ///放子
    /// id: 放子的玩家id
    /// location: 放子的棋子位置。干脆把回复消息分散到棋盘逻辑里面去。
    pub fn put(&mut self, location: &u8){
        if GameStage::Put != self.stage{
            let response = json!({"code": 302});//游戏状态不正确，当前非落子阶段
            self.black.send_message(response.to_string());
            return;
        }
        let piece = self.black.take_piece();
        match piece {
            None => {
                let response = json!({"code": 303});//游戏状态不正确，你的棋子已经放完了
                self.black.send_message(response.to_string());
            }
            Some(pc) => {
                let result = self.board.put(&location, pc);
                match result {
                    ChessResult::Ok => {
                        let three = self.board.check_three(&location, self.black.color());
                        let chessboard = self.board.point_array();
                        if three > 0{
                            if self.board.have_single_piece( self.black.color()){//判断当前对手是否有可以吃的棋子
                                //可以吃子，则转到吃子阶段，由成三方吃子
                                self.kill = three;
                                self.next.action = Action::Eat;
                                let mc = json!({"code": 0, "status": "play", "board": &chessboard, "current": {"actor": true, "action": "put", "location": &location}, "next": {"turn": true, "action": "eat"}});
                                self.black.send_message(mc.to_string());
                                let mo = json!({"code": 0, "status": "play", "board": &chessboard, "current": {"actor": false, "action": "put", "location": &location}, "next": {"turn": false, "action": "eat"}});
                                self.white.send_message(mo.to_string());
                            }else {
                                //不能吃子，则让对手下棋
                                self.kill = 0;
                                self.next.player = self.white.id();
                                let next_action = if self.black.no_piece() && self.white.no_piece(){
                                    self.board.clear_invalid_marker();
                                    self.stage = GameStage::Move;
                                    self.next.action = Action::Move;
                                    "move"
                                }else {
                                    self.next.action = Action::Put;
                                    "put"
                                };

                                mem::swap(&mut self.black, &mut self.white);
                                let mc = json!({"code": 0, "status": "play", "board": &chessboard, "current": {"actor": false, "action": "put", "location": &location}, "next": {"turn": true, "action": next_action}});
                                self.black.send_message(mc.to_string());
                                let mo = json!({"code": 0, "status": "play", "board": &chessboard, "current": {"actor": true, "action": "put", "location": &location}, "next": {"turn": false, "action": next_action}});
                                self.white.send_message(mo.to_string());
                            }
                        }else {//未成三，则要判断是否转阶段，并转交行动权
                            self.next.player = self.white.id();
                            let next_action = if self.black.no_piece() && self.white.no_piece(){
                                self.board.clear_invalid_marker();
                                self.stage = GameStage::Move;
                                self.next.action = Action::Move;
                                "move"
                            }else {
                                self.next.action = Action::Put;
                                "put"
                            };

                            mem::swap(&mut self.black, &mut self.white);
                            let mc = json!({"code": 0, "status": "play", "board": &chessboard, "current": {"actor": false, "action": "put", "location": &location}, "next": {"turn": true, "action": next_action}});
                            self.black.send_message(mc.to_string());
                            let mo = json!({"code": 0, "status": "play", "board": &chessboard, "current": {"actor": true, "action": "put", "location": &location}, "next": {"turn": false, "action": next_action}});
                            self.white.send_message(mo.to_string());
                        }
                    } ,
                    ChessResult::Error(code, message) => {
                        error!("{:?}", message);
                        let response = json!({"code": code});//游戏状态不正确，你的棋子已经放完了
                        self.black.send_message(response.to_string());
                    }
                }
            }
        }
    }

    ///吃子。只能吃对方的未成三的棋子。
    pub fn kill(&mut self, location: &u8){
        let three = self.board.check_three(&location, self.white.color());
        if three > 0{
            let response = json!({"code": 304});//该位置已成三，不能吃
            self.black.send_message(response.to_string());
            return;
        }
        let ret = match self.stage {
            GameStage::Put => {
                self.board.kill_invalid(&location, self.white.color())
            },
            GameStage::Move => {
                self.board.kill_valid(&location, self.white.color())
            },
            _ => ChessResult::Error(305, format!("Wrong game state: {:?}", self.stage)),
        };
        match ret {
            ChessResult::Ok => {
                let chessboard = self.board.point_array();
                self.kill = self.kill - 1;
                if self.board.piece_count(self.white.color()) < 3{//吃子后先判断是否赢棋
                    let mc = json!({"code": 0, "status": "over", "role": "winner", "reason": "normal", "board": &chessboard});
                    self.black.send_message(mc.to_string());
                    let mo = json!({"code": 0, "status": "over", "role": "loser", "reason": "normal", "board": &chessboard});
                    self.white.send_message(mo.to_string());
                    self.stage = GameStage::Over;
                    return;
                }
                let next_action = match self.stage {
                    GameStage::Put => "put",
                    GameStage::Move => "move",
                    _ => "error"
                };
                let times = self.kill;
                if times > 0{//还能继续吃子
                    if self.board.have_single_piece( self.white.color()){
                        let mc = json!({"code": 0, "status": "play", "board": &chessboard, "current": {"actor": true, "action": "eat", "location": &location}, "next": {"turn": true, "action": next_action}});
                        self.black.send_message(mc.to_string());
                        let mo = json!({"code": 0, "status": "play", "board": &chessboard, "current": {"actor": false, "action": "eat", "location": &location}, "next": {"turn": false, "action": next_action}});
                        self.white.send_message(mo.to_string());
                        return;
                    }
                }
                //对手行动
                mem::swap(&mut self.black, &mut self.white);
                let mc = json!({"code": 0, "status": "play", "board": &chessboard, "current": {"actor": false, "action": "eat", "location": &location}, "next": {"turn": true, "action": next_action}});
                self.black.send_message(mc.to_string());
                let mo = json!({"code": 0, "status": "play", "board": &chessboard, "current": {"actor": true, "action": "eat", "location": &location}, "next": {"turn": false, "action": next_action}});
                self.white.send_message(mo.to_string());
            },
            ChessResult::Error(code, message) => {
                error!("{:?}", message);
                let response = json!({"code": code});
                self.black.send_message(response.to_string());
            }
        }
    }

    ///走棋两个条件：
    /// 1：选择的棋子是自己的
    /// 2：只能走到相邻的空位置
    pub fn pmove(&mut self, source: &u8, target: &u8){
        if !self.board.is_near(&source, target){
            let response = json!({"code": 306, "status": "play"});
            self.black.send_message(response.to_string());
            return;
        }
        let piece = self.board.pickup(&source, self.black.color());
        match piece {
            None => {
                let response = json!({"code": 306});
                self.black.send_message(response.to_string());
            },
            Some(p) => {
                let result = self.board.put(&target, p);
                match result {
                    ChessResult::Ok => {
                        self.board.remove_piece(&source);
                        let chessboard = self.board.point_array();
                        let three = self.board.check_three(&target, self.black.color());
                        if three > 0{
                            if self.board.have_single_piece( self.black.color()){//判断当前对手是否有可以吃的棋子
                                //可以吃子，则转到吃子阶段，由成三方吃子
                                self.kill = three;
                                self.next.action = Action::Eat;
                                let mc = json!({"code": 0, "status": "play", "board": &chessboard, "current": {"actor": true, "action": "move", "source": &source, "target": &target}, "next": {"turn": true, "action": "eat"}});
                                self.black.send_message(mc.to_string());
                                let mo = json!({"code": 0, "status": "play", "board": &chessboard, "current": {"actor": false, "action": "move", "source": &source, "target": &target}, "next": {"turn": false, "action": "eat"}});
                                self.white.send_message(mo.to_string());
                            }else {
                                //不能吃子，则让对手下棋
                                self.kill = 0;
                                self.next.player = self.white.id();
                                mem::swap(&mut self.black, &mut self.white);
                                let mc = json!({"code": 0, "status": "play", "board": &chessboard, "current": {"actor": false, "action": "move", "source": &source, "target": &target}, "next": {"turn": true, "action": "move"}});
                                self.black.send_message(mc.to_string());
                                let mo = json!({"code": 0, "status": "play", "board": &chessboard, "current": {"actor": true, "action": "move", "source": &source, "target": &target}, "next": {"turn": false, "action": "move"}});
                                self.white.send_message(mo.to_string());
                            }
                        }else {//未成三，则要判断是否转阶段，并转交行动权
                            self.next.player = self.white.id();
                            mem::swap(&mut self.black, &mut self.white);
                            let mc = json!({"code": 0, "status": "play", "board": &chessboard, "current": {"actor": false, "action": "move", "source": &source, "target": &target}, "next": {"turn": true, "action": "move"}});
                            self.black.send_message(mc.to_string());
                            let mo = json!({"code": 0, "status": "play", "board": &chessboard, "current": {"actor": true, "action": "move", "source": &source, "target": &target}, "next": {"turn": false, "action": "move"}});
                            self.white.send_message(mo.to_string());
                        }
                    },
                    ChessResult::Error(code, message) => {
                        error!("{:?}", message);
                        let response = json!({"code": code});
                        self.black.send_message(response.to_string());
                    }
                }
            }
        }
    }

    ///线程循环调用room.play()方法，实现游戏活动。
    pub fn play(&mut self){
        let action = self.white.read_message();
        match action {
            Some(ref a) => {
                match a {
                    ChessAction::GiveUp() => {
                        let mc = json!({"code": 0, "status": "over", "role": "winner", "reason": "giveup"});
                        self.black.send_message(mc.to_string());
                        let mo = json!({"code": 0, "status": "over", "role": "loser", "reason": "giveup"});
                        self.white.send_message(mo.to_string());
                    },
                    ChessAction::LoseConnection() => {
                        let message = json!({"code": 0, "status": "over", "role": "winner", "reason": "lost"});
                        self.black.send_message(message.to_string());
                        error!("Opponent user {:?} lost connection!", self.white.id())
                    },
                    _ => ()
                }
            },
            None => (),
        }
        let action = self.black.read_message();
        match action {
            Some(ref a) => match &a {
                ChessAction::PutPiece(location) => {
                    if self.black.id() == self.next.player{
                        self.put(&location);
                    }else {
                        error!("Wrong user id: {}", self.black.id());
                    }
                },
                ChessAction::KillPiece(location) => {
                    if self.black.id() == self.next.player{
                        self.kill(&location);
                    }else {
                        error!("Wrong user id: {}", self.black.id());
                    }
                },
                ChessAction::MovePiece(source, target) => {
                    if self.black.id() == self.next.player{
                        self.pmove(&source, &target);
                    }else {
                        error!("Wrong user id: {}", self.black.id());
                    }
                },
                ChessAction::LoseConnection() => {
                    let message = json!({"code": 0, "status": "over", "role": "winner", "reason": "lost"});
                    self.white.send_message(message.to_string());
                    error!("Current user {:?} lost connection!", self.black.id())
                }
                _ => ()
            },
            None => ()
        }
    }
}